'''
Created on 10/10/2010

@author: syn
'''

from ui import get_save_dialog, mandatory_data_error, get_info_dialog, \
               generic_data_error, search
from ui.AddGenre import AddGenre

import gtk
from ui.GladeBase import GladeBase
from utils.Environment import logger
from utils import string_hook

from suds import WebFault
from client import client

NO_ENTITY = -1

class ManageBook(GladeBase):
    def __init__(self, query=None, top_component=None):
        logger.debug("UI: %s instance created" % self.__class__)
        GladeBase.__init__(self, 'manage_book_frame', top_component)
        
        # Setting up Books list TreeView
        cell = gtk.CellRendererText()
        tvc = gtk.TreeViewColumn('Books')
        tvc.pack_start(cell, True)
        tvc.set_attributes(cell,text=1)
        self.book_treeview.append_column(tvc)
        
        self.book_list = gtk.ListStore(int, str, object)
        self.book_list.set_sort_column_id(1, gtk.SORT_ASCENDING)
        
        try:
            books = client.service.get_books()
            if hasattr(books, 'BookSoap'):
                for book in books.BookSoap:
                    self._append_book(book)
        except WebFault, e:
            get_error_dialog(self.get_top_component(), e.message)
        
        self.book_treeview.set_model(self.book_list)
        self.book_frame_hpaned.set_position(400)
        
        # setting up genre list for treeview
        self.genre_list = gtk.ListStore(int, str)
        self.genre_list.connect('row-inserted', self.on_book_changed)
        self.genre_list.connect('row-deleted', self.on_book_changed)
        self.genre_treeview.set_model(self.genre_list)
        
        self.author_list = gtk.ListStore(int, str, str)
        self.author_list.connect('row-inserted', self.on_book_changed)
        self.author_list.connect('row-deleted', self.on_book_changed)
        self.author_treeview.set_model(self.author_list)
        
        self._init_gui_components()
        
        # Load genres combobox and author combobox
        self._load_genre_list()
        self._load_author_list()
        
        self.entity_key = NO_ENTITY
    
    def _append_book(self, book):
        """
        Add a user to the list
        """
        self.book_list.append([book.id, book.title, book])
        
    def _update_book(self, row, book):
        """
        Update a user row in model with new value
        """
        self.book_list.set(row.iter, 1, book.title, 2, book)
    
    def _init_gui_components(self):
        """
        Intialize gui components as needed. This is useful in the contructor or 
        binded with particular actions (for instance, a "clear" button, or "new" button) 
        """
        self.title_entry.set_text("")
        self.description_textbuffer.set_text("")
        
        iter = self.genre_list.get_iter_first()
        while iter:
            logger.debug("Rimuovo genere: %s " % str(iter))
            logger.debug("Generi %s " % self.genre_list.entities)
            self.genre_list.remove(iter)
            iter = self.genre_list.get_iter_first()
        
        iter = self.author_list.get_iter_first()
        while iter:
            self.author_list.remove(iter)
            iter = self.author_list.get_iter_first()
            
        self.apply_button.set_sensitive(False)
    
    def _retrieve_components(self):
        """
        Retrieve all used gui components from builder. This method is called in the
        GladeBase constructor
        """
        self.get_from_builder('book_treeview')
        self.get_from_builder('title_entry')
        self.get_from_builder('description_textview')
        self.get_from_builder('description_textbuffer')
        self.get_from_builder('genre_combobox')
        self.get_from_builder('author_combobox')
        self.get_from_builder('genre_treeview')
        self.get_from_builder('genre_treeview_menu')
        self.get_from_builder('author_treeview')
        self.get_from_builder('author_treeview_menu')
        self.get_from_builder('apply_button')
        self.get_from_builder('book_frame_hpaned')
    
    def _load_genre_list(self):
        """ Load all genres in database into combobox """
        genre_list = gtk.ListStore(int, str)
        try:
            genres = client.service.get_genres()
            if hasattr(genres, 'GenreSoap'):
                for genre in genres.GenreSoap:
                    genre_list.append([genre.id, genre.name])
        except WebFault, e:
            get_error_dialog(self.get_top_component(), e.message)
            
        self.genre_combobox.set_model(genre_list)
    
    def _load_author_list(self):
        """ Load all authors in database into combobox """
        author_list = gtk.ListStore(int, str, str)
        try:
            authors = client.service.get_authors()
            if hasattr(authors, 'AuthorSoap'):
                for author in authors.AuthorSoap:
                    author_list.append([author.id, author.name, author.surname])
        except WebFault, e:
            get_error_dialog(self.get_top_component(), e.message)
        
        self.author_combobox.set_model(author_list)
    
    def _has_valid_data(self):
        """
        Formal control for data in the input form.
        @return: boolean. 'True' when data is valid
        """
        title = self.title_entry.get_text()
        
        if not title:
            mandatory_data_error('Title', self.title_entry)
            return False
        
        if not iter(self.author_list):
            generic_data_error("Please select at least an author", self.author_combobox)
            return False
        
        return True
    
    def _save_data(self):
        """
        Save changes to db. 
        @return: 'True' if data have been successfully saved 
        """
        if not self._has_valid_data():
            return False
        
        if self.entity_key == NO_ENTITY:
            book = client.factory.service('BookSoap')
        else:
            row = search(self.book_list, (0, self.entity_key))
            book = row[2]
        
        book.title = self.title_entry.get_text()
        (start,end) = self.description_textbuffer.get_bounds()
        book.description = string_hook(self.description_textbuffer.get_text(start,end).strip())
        
        book.genres.integers = []
        for row in self.genre_list:
            book.genres.integers.append(row[0])
        book.authors.integers = []
        for row in self.author_list:
            book.authors.integers.append(row[0])
        
        # save changes
        try:
            book.id = client.service.save_book(book)
            if not book.id > 0:
                raise WebFault("Problem occurred on server during save")
            
            if self.entity_key == NO_ENTITY:
                self._append_book(book)
            else:
                # update row in list
                row = search(self.book_list, (0, book.id))
                self._update_book(row, book)
            
            self.entity_key = book.id
            self.apply_button.set_sensitive(False)
            return True
        except WebFault, e:
            get_error_dialog(self.get_top_component(), e.message)
            return False
        
        return True
    
    # Signals
    def on_book_changed(self, *args, **kwargs):
        self.apply_button.set_sensitive(True)
    
    def on_book_treeview_row_activated(self, treeview, path, view_column, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                    
        self._init_gui_components()
        
        book = self.book_list[path][2]
        self.entity_key = book.id
        
        self.title_entry.set_text(book.title)
        self.description_textbuffer.set_text(string_hook(book.description))
        
        for id in book.genres.integers:
            row = search(self.genre_combobox.get_model(), (0, id))
            self.genre_list.append(list(row))
        
        for id in book.authors:
            row = search(self.author_combobox.get_model(), (0, id))
            self.author_list.append(list(row))
        
        self.apply_button.set_sensitive(False)
            
    def on_genre_treeview_button_press(self, object, event, data=None):
        """ popup context menu on genre list when  user press right mouse button """
        if event.button == 3:
            self.genre_treeview_menu.popup(None, None, None, event.button, event.get_time())
            
    def on_author_treeview_button_press(self, object, event, data=None):
        """ popup context menu on author list when  user press right mouse button """
        if event.button == 3:
            self.author_treeview_menu.popup(None, None, None, event.button, event.get_time())
    
    def on_new_button_clicked(self, object, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                
        self._init_gui_components()
        self.book_treeview.get_selection().unselect_all()
        self.entity_key = NO_ENTITY
    
    def on_apply_button_clicked(self, object, data=None):
        self._save_data()
    
    def on_delete_button_clicked(self, object, data=None):
        (model, iter) = self.book_treeview.get_selection().get_selected()
        if not iter:
            return
        
        book = model.get_value(iter, 2)
        if len(book.products) > 0:
            get_info_dialog(self.get_top_component(),
                            "This book can't be deleted because is " \
                            "present in the product catalog. \n" \
                            "Check and remove product first.")
            return
        
        try:
            client.service.delete_book(book)
            model.remove(iter)
            
            self._init_gui_components()
            self.entity_key = NO_ENTITY
        except WebFault, e:
            get_error_dialog(self.get_top_component(), e.message)
        
    def on_new_genre_button_clicked(self, object, data=None):
        dialog = AddGenre(self.get_top_component())
        while True:
            response = dialog.run()
            if response:
                break
        dialog.destroy()
        
        if response == gtk.RESPONSE_OK:
            self._load_genre_list()
    
    def on_add_genre_button_clicked(self, object, data=None):
        iter = self.genre_combobox.get_active_iter()
        if not iter:
            return
        
        model = self.genre_combobox.get_model()
        row = model[model.get_path(iter)]
        if not search(self.genre_list, (0, row[0])):
            self.genre_list.append(list(row))
    
    def on_add_author_button_clicked(self, object, data=None):
        iter = self.author_combobox.get_active_iter()
        if not iter:
            return
            
        model = self.author_combobox.get_model()
        row = model[model.get_path(iter)]
        if not search(self.author_list, (0, row[0])):
            self.author_list.append(list(row))
            
    def on_remove_genre_activate(self, object, data=None):
        (model, iter) = self.genre_treeview.get_selection().get_selected()
        if iter:
            model.remove(iter)
            
    def on_remove_author_activate(self, object, data=None):
        (model, iter) = self.author_treeview.get_selection().get_selected()
        if iter:
            model.remove(iter)
